package com.pw.study.gmallpublisher.dao;

import com.alibaba.fastjson.JSONObject;
import com.pw.study.gmallpublisher.enties.Option;
import com.pw.study.gmallpublisher.enties.SaleDetail;
import com.pw.study.gmallpublisher.enties.Stat;
import io.searchbox.client.JestClient;
import io.searchbox.core.Search;
import io.searchbox.core.SearchResult;
import io.searchbox.core.search.aggregation.MetricAggregation;
import io.searchbox.core.search.aggregation.TermsAggregation;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

@Repository
public class ESDaoImpl implements ESDao {

    //准备JestClient
    @Autowired
    private JestClient jestClient;


    @Override
    public JSONObject getSaleDetail(String date, Integer startpage, Integer size, String keyword) throws IOException {

        JSONObject jsonObject = new JSONObject();

        SearchResult searchResult = getSearchResult(date, startpage, size, keyword);

        jsonObject.put("total", searchResult.getTotal());

        ArrayList<Stat> stats = new ArrayList<>();

        stats.add(getAgeStat(searchResult));
        stats.add(getGenderStat(searchResult));

        jsonObject.put("stats", stats);
        jsonObject.put("detail", getDetails(searchResult));


        return jsonObject;
    }

    /*
            返回年龄统计

  {
    "title": "用户年龄占比",
    "options": [
        {
            "name": "20岁到30岁",
            "value": 11.25
        },
        {
            "name": "30岁及30岁以上",
            "value": 73.85
        },
        {
            "name": "20岁以下",
            "value": 14.9
        }
    ]
}

     */
    public Stat getAgeStat(SearchResult searchResult) {

        MetricAggregation aggregations = searchResult.getAggregations();

        TermsAggregation agecount = aggregations.getTermsAggregation("agecount");

        List<TermsAggregation.Entry> buckets = agecount.getBuckets();

        double agefrom20To30 = 0d;
        double agege30 = 0d;
        double agelt20 = 0d;

        for (TermsAggregation.Entry bucket : buckets) {

            if (Integer.parseInt(bucket.getKey()) >= 30) {

                agege30 += bucket.getCount();

            } else if (Integer.parseInt(bucket.getKey()) < 20) {

                agelt20 += bucket.getCount();

            } else {

                agefrom20To30 += bucket.getCount();
            }

        }

        //计算总数
        double totalNum = agefrom20To30 + agege30 + agelt20;

        //准备计算比例
        DecimalFormat decimalFormat = new DecimalFormat("###.##%");

        ArrayList<Option> options = new ArrayList<>();

        options.add(new Option("20岁以下", decimalFormat.format(agelt20 / totalNum)));
        options.add(new Option("20岁到30岁", decimalFormat.format(agefrom20To30 / totalNum)));
        options.add(new Option("30岁及30岁以上", decimalFormat.format(agege30 / totalNum)));

        return new Stat("用户年龄占比", options);

    }

    public Stat getGenderStat(SearchResult searchResult) {

        MetricAggregation aggregations = searchResult.getAggregations();

        TermsAggregation agecount = aggregations.getTermsAggregation("gendercount");

        List<TermsAggregation.Entry> buckets = agecount.getBuckets();


        double manCount = 0d;
        double womanCount = 0d;

        for (TermsAggregation.Entry bucket : buckets) {

            if (bucket.getKey().equals("F")) {

                womanCount += bucket.getCount();

            } else {

                manCount += bucket.getCount();
            }

        }

        //计算总数
        double totalNum = manCount + womanCount;

        //准备计算比例
        DecimalFormat decimalFormat = new DecimalFormat("###.##%");

        ArrayList<Option> options = new ArrayList<>();

        options.add(new Option("男", decimalFormat.format(manCount / totalNum)));
        options.add(new Option("女", decimalFormat.format(womanCount / totalNum)));


        return new Stat("用户性别占比", options);

    }


    /*
            负责查询 detail: [  ]
     */
    public List<SaleDetail> getDetails(SearchResult searchResult) {

        List<SaleDetail> result = new ArrayList<>();

        List<SearchResult.Hit<SaleDetail, Void>> hits = searchResult.getHits(SaleDetail.class);

        for (SearchResult.Hit<SaleDetail, Void> hit : hits) {

            SaleDetail saleDetail = hit.source;

            saleDetail.setEs_metadata_id(hit.id);

            result.add(saleDetail);

        }

        return result;


    }

    /*
            date=2022-01-21&startpage=1&size=5&keyword=小米手机
     */

    public SearchResult getSearchResult(String date, Integer startpage, Integer size, String keyword) throws IOException {

        // date是为了指定查询哪一天的数据
        String indexName = "gmall2021_sale_detail" + date;

        //keyword是全文检索的关键字
        MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder("sku_name", keyword);

        // startpage 和 size用来确定从哪一天数据开始返回(from)，要返回多少条(size)
        int from = size * (startpage - 1);

        //准备Search对象
        TermsAggregationBuilder agg1 = AggregationBuilders.terms("agecount").field("user_age").size(150);

        TermsAggregationBuilder agg2 = AggregationBuilders.terms("gendercount").field("user_gender").size(3);

        String queryStr = new SearchSourceBuilder().query(matchQueryBuilder).aggregation(agg1).aggregation(agg2).from(from).size(size)
                .toString();

        Search search = new Search.Builder(queryStr).addIndex(indexName).addType("_doc").build();

        // 执行查询
        SearchResult searchResult = jestClient.execute(search);

        return searchResult;

    }
}
